package org.dousb.doupicturebackend.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.dousb.doupicturebackend.common.ErrorCode;
import org.dousb.doupicturebackend.exception.BusinessException;
import org.dousb.doupicturebackend.exception.ThrowUtils;
import org.dousb.doupicturebackend.mapper.SpaceMapper;
import org.dousb.doupicturebackend.model.dto.analyze.SpaceAnalyzeRequest;
import org.dousb.doupicturebackend.model.dto.analyze.SpaceTopNAnalzeRequest;
import org.dousb.doupicturebackend.model.dto.analyze.SpaceUsageAnalyzeRequest;
import org.dousb.doupicturebackend.model.dto.analyze.SpaceUserAnalyzeRequest;
import org.dousb.doupicturebackend.model.entity.Picture;
import org.dousb.doupicturebackend.model.entity.Space;
import org.dousb.doupicturebackend.model.entity.User;
import org.dousb.doupicturebackend.model.vo.space.analyze.*;
import org.dousb.doupicturebackend.service.PictureService;
import org.dousb.doupicturebackend.service.SpaceAnalyzeService;
import org.dousb.doupicturebackend.service.SpaceService;
import org.dousb.doupicturebackend.service.UserService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class SpaceAnalyzeServiceImpl implements SpaceAnalyzeService {

    @Resource
    private SpaceService spaceService;

    @Resource
    private UserService userService;

    @Resource
    private PictureService pictureService;

    @Resource
    private SpaceMapper spaceMapper;

    /**
     * 填充空间分析查询条件
     *
     * @param spaceAnalyzeRequest
     * @param queryWrapper
     */
    private static void fillAnalyzeQueryWrapper(SpaceAnalyzeRequest spaceAnalyzeRequest, QueryWrapper<Picture> queryWrapper) {
        if (spaceAnalyzeRequest.isQueryAll()) {
            return;
        }
        if (spaceAnalyzeRequest.isQueryPublic()) {
            queryWrapper.isNull("spaceId");
            return;
        }
        Long spaceId = spaceAnalyzeRequest.getSpaceId();
        if (spaceId != null && spaceId > 0) {
            queryWrapper.eq("spaceId", spaceId);
            return;
        }
        throw new BusinessException(ErrorCode.PARAMS_ERROR, "未指定查询范围");

    }

    /**
     * 校验空间分析权限
     *
     * @param spaceAnalyzeRequest
     */
    private void checkSpaceAnalyzeAuth(SpaceAnalyzeRequest spaceAnalyzeRequest, User loginUser) {
        //检查权限
        if (spaceAnalyzeRequest.isQueryAll() || spaceAnalyzeRequest.isQueryPublic()) {
            //全空间分析或者公共空间分析，需要管理员权限
            ThrowUtils.throwIf(!userService.isAdmin(loginUser), ErrorCode.NO_AUTH_ERROR, "无权访问公共空间");
        } else {
            //私有空间分析，需要校验空间权限
            Long spaceId = spaceAnalyzeRequest.getSpaceId();
            ThrowUtils.throwIf(spaceId == null || spaceId <= 0, ErrorCode.PARAMS_ERROR);
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
            spaceService.checkSpaceAuth(space, loginUser);
        }
    }

    /**
     * 获取空间使用分析
     *
     * @param spaceUsageAnalyzeRequest
     * @param loginUser
     * @return
     */
    @Override
    public SpaceUsageAnalyzeResponse getSpaceUsageAnalyze(SpaceUsageAnalyzeRequest spaceUsageAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceUsageAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
        if (spaceUsageAnalyzeRequest.isQueryAll() || spaceUsageAnalyzeRequest.isQueryPublic()) {
            //全空间分析或者公共空间分析，需要管理员权限
            ThrowUtils.throwIf(!userService.isAdmin(loginUser), ErrorCode.NO_AUTH_ERROR, "无权访问公共空间");
            //统计公共图库的使用情况
            QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("picSize");
            if (!spaceUsageAnalyzeRequest.isQueryAll()) {
                //全空间分析，查询所有图片
                queryWrapper.isNull("spaceId");
            }
            List<Long> picSizeList = pictureService.getBaseMapper().selectObjs(queryWrapper);
            long usedSize = picSizeList.stream()
                    .mapToLong(result -> result instanceof Long ? result : 0L)
                    .sum();
            long usedCount = picSizeList.size();
            //封装返回结果
            SpaceUsageAnalyzeResponse spaceUsageAnalyzeResponse = new SpaceUsageAnalyzeResponse();
            spaceUsageAnalyzeResponse.setUsedSize(usedSize);
            spaceUsageAnalyzeResponse.setUsedCount(usedCount);
            //公共图库 无上限 无比例
            spaceUsageAnalyzeResponse.setMaxSize(Long.MAX_VALUE);
            spaceUsageAnalyzeResponse.setSizeUsageRatio(null);
            spaceUsageAnalyzeResponse.setMaxCount(Long.MAX_VALUE);
            spaceUsageAnalyzeResponse.setCountUsageRatio(null);
            return spaceUsageAnalyzeResponse;
        } else {
            //私有空间分析，需要校验空间权限
            Long spaceId = spaceUsageAnalyzeRequest.getSpaceId();
            ThrowUtils.throwIf(spaceId == null || spaceId <= 0, ErrorCode.PARAMS_ERROR);
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
            spaceService.checkSpaceAuth(space, loginUser);
            //封装返回结果
            SpaceUsageAnalyzeResponse spaceUsageAnalyzeResponse = new SpaceUsageAnalyzeResponse();
            spaceUsageAnalyzeResponse.setUsedSize(space.getTotalSize());
            spaceUsageAnalyzeResponse.setSizeUsageRatio(NumberUtil.round(space.getTotalSize() * 100.0 / space.getMaxSize(), 2).doubleValue());
            spaceUsageAnalyzeResponse.setCountUsageRatio(NumberUtil.round(space.getTotalCount() * 100.0 / space.getMaxCount(), 2).doubleValue());
            spaceUsageAnalyzeResponse.setMaxSize(space.getMaxSize());
            spaceUsageAnalyzeResponse.setMaxCount(space.getMaxCount());
            return spaceUsageAnalyzeResponse;
        }
    }

    /**
     * 获取空间分类分析
     *
     * @param spaceUsageAnalyzeRequest 空间分析请求
     * @param loginUser                登录用户
     * @return 空间分类分析响应列表
     */
    @Override
    public List<SpaceCategoryAnalyzeResponse> getSpaceCategoryAnalyze(SpaceUsageAnalyzeRequest spaceUsageAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceUsageAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
        //检查权限
        checkSpaceAnalyzeAuth(spaceUsageAnalyzeRequest, loginUser);
        //构造查询条件
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        //根据分析范围补充查询条件
        fillAnalyzeQueryWrapper(spaceUsageAnalyzeRequest, queryWrapper);
        //使用mybatis-plus补充查询
        queryWrapper.select("category", "COUNT(*) AS count", "SUM(picSize) AS totalSize")
                .groupBy("category");
        //查询转换结果
        List<SpaceCategoryAnalyzeResponse> spaceCategoryAnalyzeResponseList = pictureService.getBaseMapper().selectMaps(queryWrapper)
                .stream()
                .map(result -> {
                    String category = result.get("category") == null ? "" : result.get("category").toString();
                    Long count = ((Number) result.get("count")).longValue();
                    Long totalSize = ((Number) result.get("totalSize")).longValue();
                    return new SpaceCategoryAnalyzeResponse(category, count, totalSize);
                })
                .collect(Collectors.toList());
        return spaceCategoryAnalyzeResponseList;
    }

    /**
     * 获取空间标签分析
     *
     * @param spaceUsageAnalyzeRequest 空间分析请求
     * @param loginUser                登录用户
     * @return 空间标签分析响应列表
     */
    @Override
    public List<SpaceTagAnalyzeResponse> getSpaceTagAnalyze(SpaceUsageAnalyzeRequest spaceUsageAnalyzeRequest, User loginUser) {
        //检查参数
        ThrowUtils.throwIf(spaceUsageAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
        //检查权限
        checkSpaceAnalyzeAuth(spaceUsageAnalyzeRequest, loginUser);
        //构造查询条件
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        fillAnalyzeQueryWrapper(spaceUsageAnalyzeRequest, queryWrapper);
        //查询符合标签的图片
        queryWrapper.select("tags");
        List<String> tagsJsonList = pictureService.getBaseMapper().selectObjs(queryWrapper)
                .stream()
                .filter(Objects::nonNull)
                .map(obj -> obj.toString())
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.toList());
        //统计标签出现次数
        Map<String, Long> tagCountMap = tagsJsonList.stream()
                .flatMap(tagsJson -> JSONUtil.toList(tagsJson, String.class).stream())
                .collect(Collectors.groupingBy(tag -> tag, Collectors.counting()));
        //封装返回结果
        List<SpaceTagAnalyzeResponse> spaceTagAnalyzeResponseList = tagCountMap.entrySet().stream()
                .sorted((e1, e2) -> e2.getValue().compareTo(e1.getValue()))
                .map(entry -> new SpaceTagAnalyzeResponse(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
        return spaceTagAnalyzeResponseList;
    }

    /**
     * 获取空间大小分析
     *
     * @param spaceUsageAnalyzeRequest 空间分析请求
     * @param loginUser                登录用户
     * @return 空间大小分析响应
     */
    @Override
    public List<SpaceSizeAnalyzeResponse> getSpaceSizeAnalyze(SpaceUsageAnalyzeRequest spaceUsageAnalyzeRequest, User loginUser) {
        //检查参数
        ThrowUtils.throwIf(spaceUsageAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
        //检查权限
        checkSpaceAnalyzeAuth(spaceUsageAnalyzeRequest, loginUser);
        //构造查询条件
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        fillAnalyzeQueryWrapper(spaceUsageAnalyzeRequest, queryWrapper);
        //查询符合条件的图片大小
        queryWrapper.select("picSize");
        List<Long> picSizeList = pictureService.getBaseMapper().selectObjs(queryWrapper)
                .stream()
                .filter(Objects::nonNull)
                .map(obj -> ((Number) obj).longValue())
                .collect(Collectors.toList());
        //统计图片大小范围出现次数
        Map<String, Long> sizeRanges = new LinkedHashMap<>();
        sizeRanges.put("<100KB", picSizeList.stream().filter(size -> size < 100 * 1024).count());
        sizeRanges.put("100KB-500KB", picSizeList.stream().filter(size -> size >= 100 * 1024 && size < 500 * 1024).count());
        sizeRanges.put("500KB-1MB", picSizeList.stream().filter(size -> size >= 500 * 1024 && size < 1024 * 1024).count());
        sizeRanges.put(">1MB", picSizeList.stream().filter(size -> size >= 1024 * 1024).count());
        //封装返回结果
        List<SpaceSizeAnalyzeResponse> spaceSizeAnalyzeResponseList = sizeRanges.entrySet().stream()
                .map(entry -> new SpaceSizeAnalyzeResponse(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
        return spaceSizeAnalyzeResponseList;
    }

    /**
     * 获取空间用户分析
     *
     * @param spaceUserAnalyzeRequest 空间分析请求
     * @param loginUser               登录用户
     * @return 空间用户分析响应列表
     */
    @Override
    public List<SpaceUserAnalyzeResponse> getSpaceUserAnalyze(SpaceUserAnalyzeRequest spaceUserAnalyzeRequest, User loginUser) {
        //检查参数
        ThrowUtils.throwIf(spaceUserAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
        //检查权限
        checkSpaceAnalyzeAuth(spaceUserAnalyzeRequest, loginUser);
        //构造查询条件
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        Long userId = spaceUserAnalyzeRequest.getUserId();
        queryWrapper.eq(ObjUtil.isNotNull(userId), "userId", userId);
        fillAnalyzeQueryWrapper(spaceUserAnalyzeRequest, queryWrapper);
        //分析维度 每日 每周 每月
        String timeDimension = spaceUserAnalyzeRequest.getTimeDimension();
        switch (timeDimension) {
            case "day":
                queryWrapper.select("date_format(createTime, '%Y-%m-%d') as period", "count(*) as count");
                break;
            case "week":
                queryWrapper.select("date_format(createTime, '%Y-%u') as period", "count(*) as count");
                break;
            case "month":
                queryWrapper.select("date_format(createTime, '%Y-%m') as period", "count(*) as count");
                break;
            default:
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "不支持的时间维度");
        }
        queryWrapper.groupBy("period").orderByAsc("period");
        //封装返回结果
        List<Map<String, Object>> queryResult = pictureService.getBaseMapper().selectMaps(queryWrapper);
        return queryResult.stream()
                .map(result -> {
                    String period = result.get("period").toString();
                    Long count = Long.parseLong(result.get("count").toString());
                    return new SpaceUserAnalyzeResponse(period, count);
                })
                .collect(Collectors.toList());
    }

    /**
     * 获取空间TopN分析
     *
     * @param spaceTopNAnalzeRequest 空间TopN分析请求
     * @param loginUser              登录用户
     * @return 空间TopN分析响应列表
     */
    @Override
    public List<Space> getSpaceTopNAnalyze(SpaceTopNAnalzeRequest spaceTopNAnalzeRequest, User loginUser) {
        //检查参数
        ThrowUtils.throwIf(spaceTopNAnalzeRequest == null, ErrorCode.PARAMS_ERROR);
        //检查权限 仅管理员
        ThrowUtils.throwIf(!userService.isAdmin(loginUser), ErrorCode.NO_AUTH_ERROR);
        //构造查询条件
        QueryWrapper<Space> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("userId", "spaceName", "id", "totalSize")
                .orderByAsc("totalSize")
                .last("LIMIT " + spaceTopNAnalzeRequest.getTopN());
        return spaceService.list(queryWrapper);
    }
}
